package com.ruoyi.quartz.task;

import com.ruoyi.quartz.domain.TempTestStatus;
import com.ruoyi.quartz.mapper.SysstatusMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.sun.management.OperatingSystemMXBean;

import javax.annotation.PostConstruct;
import java.lang.management.ManagementFactory;
import java.net.*;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Enumeration;

/**
 * 系统监控定时任务
 * 每2秒执行一次，打印CPU利用率和机器名
 * @author ruoyi
 */
@Component("ryTask")
public class RyTask {
    @Autowired
    private SysstatusMapper sysstatusMapper;
    private static final Logger log = LoggerFactory.getLogger(RyTask.class);
    private String localIp;
    // 上次CPU时间
    private long lastCpuTime = 0;
    // 上次系统时间
    private long lastSystemTime = 0;
    // 处理器数量
    private int processorCount = ManagementFactory.getPlatformMXBean(
            OperatingSystemMXBean.class).getAvailableProcessors();
    /**
     * 每2秒执行一次的系统监控任务
     */
    @Scheduled(fixedRate = 6000*60) // 固定速率执行，每隔2秒
    public void monitorSystem() throws Exception {
        // -------------------------- 需求一：定时任务：更新在线状态 --------------------------
       insertMachinenumber();
        // -------------------------- 需求四：定时任务：实时查看电脑联网状态 --------------------------

    }

    /**
     * 获取机器信息
     */
    private TempTestStatus getMachineInfo() throws UnknownHostException {
        TempTestStatus machineInfo = new TempTestStatus();
        // 获取机器名
        String hostName = InetAddress.getLocalHost().getHostName();
        // 获取CPU利用率
        int cpuUsage = (int) Math.min(Math.ceil(getCpuUsage()), 100);
        //获取ip
        String localIpAddress = getLocalIpAddress();
        log.info("机器名为:{},cpu利用率为：{},ip为：{}",hostName,cpuUsage,localIpAddress);
        LocalDateTime now = LocalDateTime.now();
        machineInfo.setSuccess(1);
        machineInfo.setIp(localIpAddress);
        machineInfo.setCpuUsage(cpuUsage);
        machineInfo.setMachineRoom(19);
        machineInfo.setMachineName(hostName);
        machineInfo.setLastUpdateTime(now);
        machineInfo.setMachineStatus(0);
        machineInfo.setLastLoginTime(now);
        return machineInfo;
    }

    /**
     * 计算CPU利用率
     */
    private double getCpuUsage() {
        OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(
                com.sun.management.OperatingSystemMXBean.class);

        // 1. 获取系统总CPU使用率（0.0~1.0）
        double systemCpuUsage = osBean.getSystemCpuLoad();

        // 2. 获取当前进程的CPU使用率（相对总CPU的比例）
        // 注意：getProcessCpuLoad() 是 Java 10+ 新增方法，返回0.0~1.0
        double processCpuUsage = osBean.getProcessCpuLoad();

        // 3. 转换为百分w比（相对系统总CPU的比例）
        return systemCpuUsage*1000 ;
    }

    /**
     * 计算IP利用率
     */
    private String getLocalIpAddress() {
        try {
            // 遍历所有网络接口
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface iface = interfaces.nextElement();
                // 过滤掉127.0.0.1和 inactive接口
                if (iface.isLoopback() || !iface.isUp()) {
                    continue;
                }

                // 遍历所有IP地址
                Enumeration<InetAddress> addresses = iface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress addr = addresses.nextElement();

                    // 只返回IPv4地址
                    if (addr instanceof Inet4Address) {
                        return addr.getHostAddress();
                    }
                }
            }
        } catch (SocketException e) {
            System.err.println("获取IP地址失败: " + e.getMessage());
        }

        // 如果没有找到合适的IP，返回环回地址
        return "127.0.0.1";
    }

    /**
     * 机器是否存在
     */
    private boolean machinAbsent(){
        String localIpAddress = getLocalIpAddress();
        boolean b = sysstatusMapper.selectByIp(localIpAddress)>0;
        if (b){
            log.info("机器ip为{}已经存在", localIpAddress);
            return true;
        }
            log.info("机器ip为{}不存在",localIpAddress);
            return false;
    }

    /**
     * true代表插入成功
     */
    private boolean insertMachinenumber() throws UnknownHostException {
        TempTestStatus machineInfo = getMachineInfo();
        if (!machinAbsent()){
            boolean insertbyip = sysstatusMapper.insertbyip(machineInfo);
            log.info("机器信息为:{},插入是否成功:{}",machineInfo,insertbyip);
        }else {
            boolean insertbyip = sysstatusMapper.updatemachineinfo(machineInfo);
            log.info("机器{}已存在,更新是否成功:{}",machineInfo,insertbyip);
        }
        return true;
    }

    /**
     * 关机时将success改为false
     */
    @PostConstruct
    public void init() {
        // 1. 获取本地IP
        localIp = getLocalIpAddress();
        log.info("初始化本地IP：{}", localIp);

        // 2. 注册JVM关机钩子（关机前执行）
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                log.info("检测到关机事件，将在线状态设为false");
                // 关机前更新success为false
                int rows = sysstatusMapper.updateSuccessByIp(localIp, 0);
                if (rows > 0) {
                    log.info("IP:{} 关机状态更新成功", localIp);
                } else {
                    log.warn("IP:{} 未在数据库中找到记录，关机状态更新失败", localIp);
                }
            } catch (Exception e) {
                log.error("关机时更新状态失败", e);
            }
        }, "ShutdownHook-UpdateStatus"));
    }

    /**
     * 实时查看电脑联网状态
     */
    private boolean checkNetworkConnectivity(String host, int port, int timeout) {
        Socket socket = null;
        try {
            socket = new Socket();
            // 尝试连接目标主机的端口，超时时间内成功则视为网络在线
            socket.connect(new InetSocketAddress(host, port), timeout);
            return true;
        } catch (Exception e) {
            // 连接失败/超时 → 网络断开
            log.debug("网络检测失败（{}:{}）：{}", host, port, e.getMessage());
            return false;
        } finally {
            // 关闭Socket释放资源
            if (socket != null && !socket.isClosed()) {
                try {
                    socket.close();
                } catch (Exception ignored) {}
            }
        }
    }

    /**
     * 实时查看电脑联网状态
     */
    @Scheduled(fixedRate = 6000*60)
    public void monitorSystemAndNetwork() {
        try {
            // 1. 检测网络状态
            boolean isNetworkOnline = checkNetworkConnectivity("www.baidu.com", 80, 2000);
            Integer success = isNetworkOnline ? 1 : 0; // 1=在线，0=离线
            // 2. 获取机器信息（CPU利用率、机器名等）
            TempTestStatus machineInfo = getMachineInfo();
            machineInfo.setSuccess(success);
            // 3. 判断机器是否存在，决定执行更新或插入
            int count = sysstatusMapper.selectByIp(localIp);
            if (count > 0) {
                // 机器存在：更新信息（包含网络状态）
                boolean updateRows = sysstatusMapper.updatemachineinfo(machineInfo);
                if (updateRows) {
                    log.info("IP:{} 信息更新成功 | 网络状态：{} | CPU利用率：{}%",
                            localIp, isNetworkOnline ? "在线" : "离线", machineInfo.getCpuUsage());
                }
            } else {
                sysstatusMapper.insertbyip(machineInfo);
                log.info("IP:{} 首次上线，已插入记录 | 网络状态：{}",
                        localIp, isNetworkOnline ? "在线" : "离线");
            }
        } catch (Exception e) {
            log.error("系统与网络监控任务执行失败", e);
        }
    }
    /**
     * 定时任务：每小时执行一次
     * cron表达式：0 0 * * * ? 表示每小时0分0秒执行
     */
    @Scheduled(cron = "0 0 12 * * ?")
//    @Scheduled(cron = "* * * * * ?")
    public void checkAndUpdateMachineStatus() {
        try {
            TempTestStatus machineInfo = getMachineInfo();
            String ip = machineInfo.getIp();
            // 1. 计算阈值时间：当前时间减去3天
            LocalDateTime thresholdTime = LocalDateTime.now().minus(3, ChronoUnit.DAYS);
//            LocalDateTime thresholdTime = LocalDateTime.now().minus(0, ChronoUnit.SECONDS);
            log.info("开始检查超过3天未更新的机器，最晚开机时间：{}", thresholdTime);

            // 2. 执行更新：将last_update_time早于阈值时间的机器状态设为1
            int updateRows = sysstatusMapper.updateMachineStatusByLastUpdateTime(ip);


            // 3. 记录结果日志
            log.info("机器状态检查完成，共更新{}台超过3天未活跃的机器", updateRows);

        } catch (Exception e) {
            log.error("机器状态检查任务执行失败", e);
        }
    }

}
